<template>
  <div class="">
    <!-- 上传 -->
    <el-upload ref="upload" :on-remove="onImgRemove" :on-preview="handlePictureCardPreview" class="upload-demo"
               action="#"
               :auto-upload="false"
               :on-change="uploadChange"
               :before-upload="beforeUpload"
               accept=".mp4,.mov,.png,.jpeg,.jpg,.pdf,.docx" multiple
               :show-file-list="buttonType==='i'"
               :file-list="fileList.length!==0?fileList:showListData" :list-type="buttonType==='i'?'picture-card':''"
    >
      <el-button size="small" type="primary" icon="el-icon-upload" v-if="buttonType==='button'">{{ title }}</el-button>
      <i class="el-icon-plus" v-if="buttonType==='i'"/>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="dialogImageUrl+'?'+$globalImageProcessingSuffix" alt="">
    </el-dialog>
    <!-- 上传列表 -->
    <el-dialog
      :before-close="beforeClose"
      :close-on-click-modal="false"
      append-to-body
      title="上传列表"
      :visible.sync="show_upload"
      @open="open"
      @close="close"
      width="40%"
    >
      <div>
        <div style="color: red">{{ errorMessageFileName }}</div>
        <div style="color: red">{{ errorMessageFileTypeImg }}</div>
        <div style="color: red">{{ errorMessageFileTypeVideo }}</div>
        <div>上传进度:{{ uploadCount }}/{{ list.length }}</div>
        总大小：{{
          parseInt(totalSize / 1024 / 1024) === 0 ? "(" + (totalSize / 1024).toFixed(2) + "KB)" : "(" + (totalSize / 1024 / 1024).toFixed(2) + "M)"
        }}

        <el-button @click.stop="startUp()">开始上传</el-button>
      </div>
      <el-scrollbar style="height:400px;">


        <div class="dis-flex flex-wrap margin-t10">
          <div v-for="(item,index) in list" :key="index"
               style="width: 100%;border:1px solid #F2F6FC;margin-bottom: 5px;">
            <div class="w-100" style="position: relative;">
              <div
                style="position: absolute;width: 100%;height: 45px;display: flex;align-items: center;text-align: center;"
              >
                <div style="width: 100%;font-size: 12px;">
                  <div style="flex: 1;">{{ item.name }}</div>
                  <div style="display: flex; justify-content: center; align-items: center;">
                    <div style="font-weight: bold;">{{ parseInt(item.percent) }}%</div>
                    <div style="font-weight: bold;">{{
                        parseInt(item.size / 1024 / 1024) === 0 ? "(" + (item.size / 1024).toFixed(2) + "KB)" : "(" + (item.size / 1024 / 1024).toFixed(2) + "M)"
                      }}
                    </div>
                    <div style="font-weight: bold;">{{ "------" + item.status }}</div>
                  </div>

                </div>
                <div style="width: 80px;">
                  <div v-if="item.is_cancel == 0 && item.percent < 100&& item.percent !== 0" @click="cancel(index)"><i
                    class="el-icon-circle-close"
                  ></i></div>
                  <div v-if="item.is_cancel == 1" style="font-size: 10px;">已取消</div>
                  <div v-if="item.is_cancel == 0 && item.percent >= 100" style="font-size: 18px;color: #fff;"><i
                    class="el-icon-success"
                  ></i></div>
                </div>
              </div>
              <div class="jdy-progress-bar"
                   :style="{ width: item.percent+'%' ,background:getGradient(item.percent)}"
              ></div>
            </div>
          </div>
        </div>
      </el-scrollbar>
      <div style="text-align:right;">
        <el-button type="danger" @click="closeDialog">取消</el-button>
        <el-button type="primary" @click="confirmBatch">确定</el-button>
      </div>

    </el-dialog>
  </div>
</template>
<script>
import * as qiniu from 'qiniu-js'
import {getQiniuToken, toWaterMark} from '../../api/qiniu'
import {addFile, validateFileSize} from "../../api/file";

export default {
  props: {
    title: String,
    type: {
      type: Number,
      default: 1
    },
    source: {
      type: Number,
      default: 1
    },
    buttonType: {
      type: String,
      default: 'button'
    },
    value: {
      type: String,
      default: ''
    },
    isWatermark: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      queue: [],
      uploadingCount: 0,
      maxUploadingCount: 1,
      lastFileCount: 0,
      fileAllList: [],
      errorMessageFileName: '',
      errorMessageFileTypeImg: '',
      errorMessageFileTypeVideo: '',
      errorFileNameList: [],
      errorFileTypeImgList: [],
      errorFileTypeVideoList: [],
      showListData: [],
      dialogImageUrl: '',
      dialogVisible: false,
      listPercent: [],
      urlList: [],
      uploadPreImg: '', //上传七牛的文件前缀
      domainImg: '',//七牛云解析域名
      qiniuTokenImg: '', //七牛Token
      uploadPreVideo: '', //上传七牛的文件前缀
      domainVideo: '',//七牛云解析域名
      qiniuTokenVideo: '', //七牛Token
      index: 0,
      list: [],
      uploadCount: 0,
      totalSize: 0.00,
      show_upload: false,
      linearColors: [{v: 25, s: '#F7564A', e: '#F7564A'}, {v: 50, s: '#F7564A', e: '#F7E04B'}, {
        v: 100,
        s: '#F7E04B',
        e: '#25CCDB',
        ef: true
      }, {v: 100, s: '#25CCDB', e: '#25CCDB'}]
    }
  },
  created() {

    this.getQiniuTokenParam(this.type)

  },
  computed: {
    fileList: {
      get: function () {
        return this.initFileList()
      },
      set: function () {
      }
    }
  },
  methods: {
    addFileInfo(file, url) {
      let formData = {
        "fileName": file.name,
        "fileUrl": url,
        "fileSize": file.size,
        "fileType": file.type,
        "sourceType": 1//素材
      }

      addFile(formData).then(() => {

      })
    },
    uploadChange(file, fileList) {
      this.show_upload = true
      let typeArr = file.raw.type.split('/')
      if (this.type == 1 && typeArr[0] != 'image') {
        this.errorFileTypeImgList.push(file.name)
        // this.$message.error('图片文件格式错误!不支持' + file.type + '文件')
        // return false // 终止上传
      } else if (this.type == 2 && typeArr[0] != 'video') {
        this.errorFileTypeVideoList.push(file.name)
        // this.$message.error('视频文件格式错误!不支持' + file.type + '文件')
        // return false // 终止上传
      } else {
        this.fileAllList.push(file)
        this.uploadVideo(file)
      }
    },
    startUp() {
      if (this.queue.length > 0) {
        this.$notify({
          title: '失败',
          message: "上传队列已经有数据了，请勿重复操作",
          type: 'error',
          duration: 2000
        })
        return
      }

      if (this.uploadCount > 0 && this.uploadCount !== this.list.length) {
        this.$notify({
          title: '失败',
          message: "任务正在进行时，请勿重复操作",
          type: 'error',
          duration: 2000
        })
        return
      }

      if (this.uploadCount === this.list.length) {
        this.$notify({
          title: '失败',
          message: "所有任务已经完成，请勿重复操作",
          type: 'error',
          duration: 2000
        })
        return
      }
      let uploadTotalSize = 0
      this.fileAllList.forEach(item => {
        uploadTotalSize = uploadTotalSize + item.size
      })
      if (this.source === 1) {
        //如果是素材
        validateFileSize({"uploadTotalSize": uploadTotalSize}).then(response => {
          this.fileAllList.forEach(item => {
            this.addFile(item); // 添加文件到队列中
          })
        })
      } else if (this.source === 2) {
        //如果是商品
        this.fileAllList.forEach(item => {
          this.addFile(item); // 添加文件到队列中
        })
      }


    },
    initFileList() {
      let val = []
      if (this.value) {
        let imgList = this.value.split('|')
        imgList.forEach(function (item, index) {
          let imgForm = {
            name: index,
            url: item
          }
          val.push(imgForm)
        })
      }
      return val
    },
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url
      this.dialogVisible = true
    },
    onImgRemove(file, fileList) {
      this.showListData = fileList
      let temp = []
      fileList.forEach(function (item) {
        temp.push(item)
      })
      this.$emit('input', this.arraysToString(temp))
    },
    arraysToString(fileList) {
      if (fileList && fileList.length > 0) {
        let temp = ''
        fileList.forEach(function (item) {
          temp = temp + '|' + item.url
        })
        return temp.substring(1)
      }
    },
    closeDialog() {
      this.show_upload = false
      this.fileAllList.forEach(item => {
        this.$refs.upload.handleRemove(item)
      })
    },
    beforeClose() {
      this.show_upload = false
      this.fileAllList.forEach(item => {
        this.$refs.upload.handleRemove(item)
      })
    },
    close() {
      this.errorMessageFileName = ''
      this.errorFileNameList = []

      this.errorMessageFileTypeImg = ''
      this.errorFileTypeImgList = []

      this.errorMessageFileTypeVideo = ''
      this.errorFileTypeVideoList = []
      //重置限制
      // this.$refs.upload.clearFiles()
      //窗口关闭时取消所有进度
      this.list.forEach((item, index) => {
        this.cancel(index)
      })


      this.queue = []
      this.fileAllList = []
      this.list = []
      this.index = 0
      this.urlList = []
      this.uploadCount = 0
      this.uploadingCount = 0
      this.maxUploadingCount = 3
    },
    open() {
      //去重
      this.errorFileNameList = Array.from(new Set(this.errorFileNameList))
      if (this.errorFileNameList.length > 0) {
        //如果有错误
        let errorFileListStr = ''
        this.errorFileNameList.forEach(item => {
          errorFileListStr = errorFileListStr + '，【' + item + '】'
        })
        this.errorMessageFileName = '以下文件名称含特殊字符，请修改后上传：' + errorFileListStr.substring(1)
      }

      this.errorFileTypeImgList = Array.from(new Set(this.errorFileTypeImgList))
      if (this.errorFileTypeImgList.length > 0) {
        //如果有错误
        let errorFileListStr = ''
        this.errorFileTypeImgList.forEach(item => {
          errorFileListStr = errorFileListStr + '，【' + item + '】'
        })
        this.errorMessageFileTypeImg = '以下文件类型不属于图片请查证：' + errorFileListStr.substring(1)
      }

      this.errorFileTypeVideoList = Array.from(new Set(this.errorFileTypeVideoList))
      if (this.errorFileTypeVideoList.length > 0) {
        //如果有错误
        let errorFileListStr = ''
        this.errorFileTypeVideoList.forEach(item => {
          errorFileListStr = errorFileListStr + '，【' + item + '】'
        })
        this.errorMessageFileTypeVideo = '以下文件类型不属于视频请查证：' + errorFileListStr.substring(1)
      }

    },
    confirmBatch() {
      let flag = true
      this.list.forEach(item => {
        if (item.percent !== 100 && item.is_cancel === 0) {
          flag = false
        }
      })
      if (!flag) {
        this.$notify({
          title: '失败',
          message: '请等待所有文件上传成功 或 出现了网络问题，请刷新页面重新上传！',
          type: 'error',
          duration: 2000
        })
      } else {
        //请求父组件，添加素材列表
        this.urlList.forEach((item, index) => {
          let param = {
            'name': index,
            'url': item.url
          }
          this.showListData.push(param)
        })

        this.$emit('successCBK', this.urlList)
        this.show_upload = false
      }
    },
    toWaterMark(url) {
      toWaterMark({'type': this.type, 'url': url}).then(response => {

      })
    },
    hasSpecialSymbols(str) {
      var regex = /[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/
      return regex.test(str)
    },
    removeSpecialCharacters(str) {
      return str.replace(/[^\w\s]/gi, '') // 使用正则表达式 /[^\w\s]/g 匹配非单词、非空白字符并全局替换为空字符串 ''
    },
    beforeUpload(file) {

      // this.show_upload = true
      // this.fileAllList.push(file)
      // //检查文件的名称(这里暂不做限制，上传之前修改文件名，去除特殊字符)
      // // var period = file.name.lastIndexOf('.')
      // // var splitFileName = file.name.substring(0, period)
      // // if (this.hasSpecialSymbols(splitFileName)) {
      // //   this.errorFileNameList.push(file.name)
      // //   // this.$message.error('文件名称中存在特殊字符请修改后上传：' + splitFileName + '文件')
      // //   return false // 终止上传
      // // }
      // let typeArr = file.type.split('/')
      // if (this.type == 1 && typeArr[0] != 'image') {
      //   this.errorFileTypeImgList.push(file.name)
      //   // this.$message.error('图片文件格式错误!不支持' + file.type + '文件')
      //   return false // 终止上传
      // } else if (this.type == 2 && typeArr[0] != 'video') {
      //   this.errorFileTypeVideoList.push(file.name)
      //   // this.$message.error('视频文件格式错误!不支持' + file.type + '文件')
      //   return false // 终止上传
      // } else {
      //   // this.getQiniuToken(file)
      //   this.uploadCount++
      //   if (this.uploadCount<=5*this.index){
      //     this.uploadVideo(file, this.index)
      //     this.index = this.index + 1
      //   }
      // }
    },
    uploadVideo(file) {
      this.totalSize = this.totalSize + file.size
      const _this = this
      let indexd = file.name.lastIndexOf('.')
      let suffix = file.name.substring(indexd)
      let prefix = file.name.substring(0, indexd)
      //判断是否有特殊字符
      if (this.hasSpecialSymbols(prefix)) {
        prefix = this.removeSpecialCharacters(prefix)
      }
      let token = ''
      let domain = ''
      let uploadPre = ''
      if (_this.type === 1) {
        token = _this.qiniuTokenImg
        domain = _this.domainImg
        uploadPre = _this.uploadPreImg
      } else {
        token = _this.qiniuTokenVideo
        domain = _this.domainVideo
        uploadPre = _this.uploadPreVideo
      }
      // key：文件资源名，为空字符串时则文件资源名也为空，为 null 或者 undefined 时则自动使用文件的 hash 作为文件名
      const key = uploadPre + '/' + prefix + '_' + Date.now() + suffix
      _this.list.push({
        size: file.size,
        is_cancel: 0, //是否取消
        name: key, //上传文件名
        percent: 0, //进度
        subscription: null, //取消对象
        imgLink: '', //缩略图
        status: "等待上传"
      })

    },
    addFile(file) {
      this.queue.push(file)
      this.uploadFiles()
    },
    async uploadFiles() {
      if (this.queue.length === 0) {
        return
      }
      while (this.uploadingCount < this.maxUploadingCount && this.queue.length > 0) {

        const file = this.queue.shift()
        const uploadPromise = this.uploadToQiniu(file, this.index)
          .then(() => {
            this.uploadingCount--
          })
          .catch((err) => {
            console.error('Failed to upload file:', file.name, err)
            this.uploadingCount--
          })

        this.index = this.index + 1
        this.uploadingCount++
        await uploadPromise
      }
    },

    async uploadToQiniu(file, index) {
      await new Promise((resolve, reject) => {
        //_this.qiniuToken 由后端提供，通过接口获取
        const _this = this

        let indexd = file.name.lastIndexOf('.')
        let suffix = file.name.substring(indexd)
        let prefix = file.name.substring(0, indexd)
        //判断是否有特殊字符
        if (this.hasSpecialSymbols(prefix)) {
          prefix = this.removeSpecialCharacters(prefix)
        }
        let token = ''
        let domain = ''
        let uploadPre = ''
        if (_this.type === 1) {
          token = _this.qiniuTokenImg
          domain = _this.domainImg
          uploadPre = _this.uploadPreImg
        } else {
          token = _this.qiniuTokenVideo
          domain = _this.domainVideo
          uploadPre = _this.uploadPreVideo
        }
        const key = uploadPre + '/' + prefix + '_' + Date.now() + suffix
        var observable = qiniu.upload(file.raw, key, token, {
          useCdnDomain: true,
          region: qiniu.region.z0, // 根据地区不同，官网有不同的配置
          concurrentRequestLimit: 1000
        })

        var observer = {
          next(res) { // 用于展示上传进度
            _this.list[index].status = "上传中......"
            _this.list[index].percent = res.total.percent
          },
          error(err) {
            reject(new Error('Failed to upload file'))
            console.log({err})
            _this.$message({
              type: 'warning',
              message: err.message + ',刷新页面重试!'
            })
          },
          complete(res) {
            _this.uploadCount++
            _this.list[index].status = "完成"
            resolve()
            let url = domain + '/' + res.key
            if (_this.source === 1) {
              //如果是素材才添加文件
              _this.addFileInfo(file, url)
            }


            let urlParam = {'url': url, 'index': index}
            _this.urlList.push(urlParam)
            if (_this.isWatermark) {
              _this.toWaterMark(url)
            }
          }
        }
        _this.list[index].subscription = observable.subscribe(observer) // 开始上传（赋值给一个全局的参数，可以在合适的时机通过：subscription.unsubscribe() 终止上传）
      })

    },
    //取消上传
    cancel(index) {
      if (this.list[index].subscription) {
        this.list[index].subscription.unsubscribe()
      }
      this.list[index].is_cancel = 1
    },
    //获取Token
    getQiniuTokenParam(type) {//1图片 2视频
      getQiniuToken({'type': type}).then(res => {
        if (res.code == 200) {
          if (type === 1) {
            this.qiniuTokenImg = res.data.qiniuToken
            this.domainImg = res.data.domain
            this.uploadPreImg = res.data.uploadPre
          } else {
            this.qiniuTokenVideo = res.data.qiniuToken
            this.domainVideo = res.data.domain
            this.uploadPreVideo = res.data.uploadPre
          }
        }
      })
    },
    // 选取文件超过数量提示
    handleExceed(files, fileList) {
      this.$message.warning(`最多可选择5个文件,本次选择了 ${files.length} 个文件`)
    },
    getGradient(percentage) {
      let linecolor = this.getColorItem(percentage)
      if (linecolor) {
        return 'linear-gradient(90deg,' + linecolor.s + ',' + linecolor.e + ')'
      } else {
        return ''
      }
    },
    // 根据进度 获取颜色数组
    getColorItem(p) {
      let mp = p
      for (let sub of this.linearColors) {
        if (!sub.ef && mp <= sub.v) {
          return sub
        } else if (sub.ef && mp < sub.v) {
          return sub
        }
      }
      return null
    }
  }
}
</script>
<style>
.jdy-progress-bar {
  transition: width 1s;
  height: 45px;
}

</style>

